package org.zw.android.framework.impl;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.zw.android.framework.async.AsyncTaskExecutor;
import org.zw.android.framework.async.AsyncTaskRunnable;
import org.zw.android.framework.cache.ImageCallback;
import org.zw.android.framework.cache.ImageDownloader;
import org.zw.android.framework.cache.DiskLruCache.Editor;
import org.zw.android.framework.cache.DiskLruCache.Snapshot;
import org.zw.android.framework.cache.ImageDownloader.State;
import org.zw.android.framework.cache.ImageOption;
import org.zw.android.framework.util.BitmapUtils;
import org.zw.android.framework.util.StringUtils;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
import android.widget.ImageView;

/**
 * Asynchronous loading Bitmap Implements
 * 
 * @author zhouwei
 *
 */
public final class ImageCooler {
	
	private static ImageDownloader downloader ;
	
	/**
	 * init ImageCooler
	 */
	public static void config(Context context,
			String cacheName,
			float percent, 
			int version){
		
		if(downloader == null){
			
			 long maxMem		= Runtime.getRuntime().maxMemory() ;
			 int cacheSize 		= Math.round(percent * maxMem);
			 
			 downloader = ImageDownloader.open(context, cacheName, cacheSize, version <= 0 ? 1 : version);
		}
	}
	
	/**
	 * download bitmap
	 */
	public static void request(ImageView imageView, String url, ImageOption op){
		
		if(imageView == null || StringUtils.isEmpty(url)) return ;
		
		if(downloader != null){
			downloader.fetchImage(url, imageView, op);
		}
	}

	/**
	 * download bitmap
	 */
	public static ImageRequest request(ImageView view){
		
		if(downloader == null){
			Log.e("ImageCool", "ERROR: Please first call ImageCool.config(...)");
			return null ;
		}
		
		if(view == null){
			Log.e("ImageCool", "ERROR: ImageView is null");
			return null ;
		}
		
		return new ImageRequest(view) ;
	}
	
	public static void fetchImage(final String url,final boolean decode,final DownloadImageCallback callback){
		
		if(StringUtils.isEmpty(url)) return ;
		
		// execute download url
		AsyncTaskExecutor.execute(new AsyncTaskRunnable() {
			
			@Override
			public Object onProcessing() {
				
				InputStream input = null ;
				OutputStream out = null ;
				Editor editor = null ;
				Snapshot shot = null ;
				Bitmap bitmap = null ;
				try{
					
					// exist in cache
					shot = downloader.getCacheSnapshot(url);
					if(shot != null){
						
						File file = shot.getCleanFile(0);
						
						if(decode)
							bitmap = BitmapUtils.createBitmap(file.getAbsolutePath(), -1, -1) ;
						
						if(callback != null){
							callback.onFinish(url, file.getAbsolutePath(), bitmap);
						}
					} else {
						
						// download
						URL u = new URL(url.trim());
						HttpURLConnection connection = (HttpURLConnection) u.openConnection();
						connection.setConnectTimeout(6000);
						connection.setReadTimeout(6000);
						connection.setRequestMethod("GET");
						connection.connect();
						
						final int total = connection.getContentLength();
						input = connection.getInputStream() ;
						
						// cache editor
						editor = downloader.getCacheEditor(url);
						
						out = editor.newOutputStream(0);
						byte[] buf = new byte[4 * 1024] ;
						int read = -1 ;
						int count = 0;
						
						while((read = input.read(buf)) > 0){
							
							out.write(buf,0,read);
							out.flush() ;
							count += read ;
							
							if(callback != null){
								callback.onProcess(url, total, count);
							}
						}
						
						// save
						editor.commit() ;
						
						// flush
						downloader.flushCache();
						
						// get file
						shot = downloader.getCacheSnapshot(url);
						if(shot != null){
							
							File file = shot.getCleanFile(0);
							
							if(decode)
								bitmap = BitmapUtils.createBitmap(file.getAbsolutePath(), -1, -1) ;
							
							if(callback != null){
								callback.onFinish(url, file.getAbsolutePath(), bitmap);
							}
						}
					}
				} catch(Exception e){
					
					e.printStackTrace() ;
					
					// callback error
					if(callback != null){
						callback.onError(e);
					}
					
					if(editor != null) {
						try {
							editor.abort() ;
						} catch (IOException e1) {
							// ignore
						}
					}
				} finally{
					try {
						if (input != null)
							input.close();
						if (out != null)
							out.close();
					} catch (IOException e1) {
						// ignore
					}
				}
				
				return null;
			}
		}) ;
	}
	
	public static Bitmap getBitmap(String url) {
		return downloader != null ? downloader.getBitmapFromCache(url) : null;
	}

	public static Bitmap getBitmap(String url, ImageOption op) {
		return downloader != null ? downloader.getBitmapFromCache(url,op) : null;
	}
	
	public static void clearBitmap(String url){
		if(downloader != null){
			downloader.clearBitmap(url);
		}
	}
	
	public static void clearBitmap(String url,ImageOption op){
		if(downloader != null){
			downloader.clearBitmap(url,op);
		}
	}

	public static String getCacheLocalPath(String url) {
		return downloader != null ? downloader.getBitmapCachePath(url) : null;
	}

	public static void onStart() {
		if(downloader != null){
			downloader.onStart() ;
		}
	}

	public static void onPause() {
		if(downloader != null){
			downloader.onPause() ;
		}
	}

	public static void onResume() {
		if(downloader != null){
			downloader.onResume() ;
		}
	}

	public static void onDestory() {
		if(downloader != null){
			downloader.onDestory() ;
		}
	}

	public static void setState(State newState) {
		if(downloader != null){
			downloader.setDownloadStatus(newState) ;
		}
	}

	public static State getState() {
		return downloader != null ? downloader.getDownloadStatus() : State.STATE_OFF ;
	}
	
	public static long cacheFileSize(){
		return downloader != null ? downloader.cacheFileSize() : 0 ;
	}
	
	public static long cacheMemorySize(){
		return downloader != null ? downloader.cacheMemorySize() : 0 ;
	}

	public static void clearDiskCache() {
		if(downloader != null){
			downloader.clearData() ;
		}
	}
	
	public static void releaseMemory(){
		if(downloader != null){
			downloader.releaseMemory() ;
		}
	}

	public static void onCancelTask() {
		if(downloader != null){
			downloader.onCancelTask() ;
		}
	}
	
	/**
	 * Image Request
	 * @author zhouwei
	 *
	 */
	public static class ImageRequest{
		
		private ImageView				mView ;
		private String 					mUrl ;
		private ImageOption 			mOption ;
		
		public ImageRequest(ImageView view){
			mView		= view ;
			mOption 	= new ImageOption();
		}
		
		public ImageRequest withCallback(ImageCallback callback){
			mOption.setCallback(callback);
			return this ;
		}
		
		public ImageRequest withDefault(int drawable){
			mOption.setDefaultResid(drawable);
			return this ;
		}
		
		public ImageRequest withError(int drawable){
			mOption.setErrorResid(drawable);
			return this ;
		}
		
		public ImageRequest withFadeIn(boolean fadein){
			mOption.setFadeIn(fadein);
			return this ;
		}
		
		public ImageRequest withFadeDuration(int duration){
			mOption.setFadeDuration(duration);
			return this ;
		}
		
		public ImageRequest withUrl(String url){
			mUrl	= url ;
			return this ;
		}
		
		public ImageRequest withViewWidth(int width){
			mOption.setViewWidth(width);
			return this ;
		} 
		
		public ImageRequest withViewHeight(int height){
			mOption.setViewHeight(height);
			return this ;
		} 
		
		public ImageRequest withDecodeWidth(int width){
			mOption.setWidth(width);
			return this ;
		} 
		
		public ImageRequest withDecodeHeight(int height){
			mOption.setHeight(height);
			return this ;
		} 
		
		public boolean fetch(){
			
			if(mView == null 
					|| downloader == null
					|| StringUtils.isEmpty(mUrl)) return false ;
			
			downloader.fetchImage(mUrl, mView, mOption);
			
			return true ;
		}
	}
	
	// download callback
	public static interface DownloadImageCallback {
		
		public void onProcess(String url ,int total,int readCount) ;
		
		public void onFinish(String url,String path,Bitmap src) ;
		
		public void onError(Exception e) ;
	}
}
